# Informe Técnico de Revisión — Sistema de Gestión de Inventario, Ventas y Control Financiero Multimoneda

## 1. Resumen ejecutivo

La propuesta original está bien pensada conceptualmente: identifica correctamente que el problema central no es "un inventario", sino un sistema de **contabilidad gerencial multimoneda con trazabilidad de costos**. El principio de usar USDT como moneda contable, congelar tasas por transacción y separar capital/ingreso/utilidad/retiro es sólido y es exactamente lo que evita los errores típicos de negocios que operan en economías con doble tipo de cambio.

Dicho esto, el documento es una **especificación funcional/conceptual**, no un diseño técnico ejecutable. Faltan decisiones críticas de ingeniería que determinan si el sistema va a ser mantenible a los 12–24 meses: modelado de dinero, particionamiento de tablas de alto volumen (movimientos de inventario, tasas), estrategia de concurrencia, versión de FIFO por variante vs. por lote agregado, testing, CI/CD y separación entre "MVP" real y "wishlist".

A continuación el análisis por capa, con lo que sí está bien resuelto y lo que necesita definirse antes de escribir código.

---

## 2. Infraestructura

### 2.1 Lo que está bien planteado
- Monolito modular en lugar de microservicios: correcto para el tamaño del negocio. Microservicios aquí solo añadirían complejidad operativa sin beneficio real.
- Separación lógica por dominios (`Inventory`, `Sales`, `Finance`, `ExchangeRates`, `Partners`) es la base correcta para, si algún día se necesita, extraer servicios.
- Uso de colas y scheduler para actualización de tasas es apropiado.

### 2.2 Lo que falta definir
- **Entornos**: no se menciona staging. Con lógica financiera (tasas, utilidades, distribución de socios) es indispensable tener un entorno de staging con datos realistas antes de tocar producción.
- **Contenedores**: el documento asume Linux + Nginx + PHP-FPM "a pelo". Se recomienda Docker/Docker Compose desde el día uno (incluso sin Kubernetes) para que el entorno de desarrollo sea reproducible y el despliegue sea determinista.
- **CI/CD**: no aparece en ninguna sección. Para un sistema donde un bug en `PricingService` o en el cálculo FIFO puede generar pérdidas reales, se necesita pipeline con tests automáticos antes de cada despliegue (GitHub Actions es suficiente).
- **Redis**: se menciona pero no se define su uso. Debería usarse explícitamente para: cache de tasas vigentes, colas (`Laravel Queue`), y rate-limiting de las consultas a fuentes externas de tasas.
- **Backups**: la política (7 diarios / 4 semanales / 3 mensuales) es razonable, pero falta el punto más importante: **pruebas de restauración periódicas**. Un backup no probado no es un backup.
- **Secretos**: no se menciona gestión de credenciales (API keys de fuentes de tasas, credenciales de BD). Usar `.env` + un vault mínimo (o al menos variables de entorno gestionadas por el proveedor) desde el inicio.

### 2.3 Sugerencia de infraestructura mínima viable
```
Producción:
  - 1 VPS/VM para app (Nginx + PHP-FPM + Laravel)
  - 1 instancia PostgreSQL gestionada (con réplica de lectura si el presupuesto lo permite)
  - 1 instancia Redis
  - Backups automatizados fuera del servidor (S3-compatible)
  - Monitoreo básico: Laravel Telescope en staging, Sentry en producción
```

---

## 3. Desarrollo / arquitectura de aplicación

### 3.1 Fortalezas
- La idea de no poner lógica en controladores y usar `Services`/`Actions` es correcta.
- Reconocer que las tasas deben "congelarse" dentro de la transacción es el punto de diseño más importante de todo el documento — hay que protegerlo con tests, no solo con buenas intenciones.

### 3.2 Riesgos de diseño que hay que resolver antes de codificar

**a) FIFO real vs. FIFO declarado**
El documento describe FIFO conceptualmente pero no resuelve el modelo de datos que lo soporta. FIFO exige que cada `sale_item` pueda quedar vinculado a **uno o más lotes de origen** (una venta de 120 unidades puede consumir dos lotes distintos, como el propio ejemplo lo muestra). Esto requiere una tabla intermedia:
```
sale_item_lot_consumptions
  sale_item_id
  inventory_lot_id
  quantity
  unit_cost_usdt (snapshot, no referencia al lote actual)
```
Sin esta tabla, "costo real vendido" será una aproximación, no un dato auditable.

**b) Snapshot de tasas y costos, no solo referencia por FK**
El documento dice correctamente "no recalcular históricamente", pero para que esto funcione en la práctica hay que **desnormalizar deliberadamente**: cada venta, compra, gasto y conversión debe guardar los valores numéricos usados (tasa BCV, tasa USDT, costo unitario) como columnas propias, no solo un `exchange_rate_id`. Si mañana se corrige un registro de tasa por error de captura, ninguna transacción histórica debe moverse.

**c) Concurrencia sobre inventario**
Con ventas simultáneas desde Venezuela y Colombia, hace falta bloqueo pesimista (`SELECT ... FOR UPDATE`) o control optimista con versión en la fila de stock por variante/ubicación, para evitar sobreventa. El documento menciona "impedir vender stock inexistente" como regla de integridad, pero eso se implementa a nivel de transacción de aplicación + constraint, no solo constraint.

**d) Testing**
No se menciona una sola vez. Dado que este sistema hace cálculos financieros (margen, utilidad, distribución de socios, diferencia cambiaria), se necesita:
- Tests unitarios de `PricingService`, `ProfitService`, `ExchangeRateService` (estos son los que más van a cambiar y más daño hacen si fallan).
- Tests de integración para el flujo completo de venta (transacción atómica con rollback).
- Al menos un test de "congelamiento de tasa" que falle si alguien intenta recalcular una venta histórica con tasa actual.

**e) Idempotencia en jobs de tasas**
El scheduler que actualiza tasas cada 30–60 min necesita ser idempotente y tolerante a fallos de la fuente externa (reintentos con backoff, alerta si la fuente falla más de N veces seguidas, y un valor "última tasa válida" para no dejar el sistema sin tasa de referencia).

### 3.3 Servicios de dominio — ajuste sugerido
La lista propuesta está bien, pero conviene separar explícitamente lectura de escritura en los servicios más sensibles:
```
PricingService        → cálculo (puro, sin efectos secundarios)
SalesService           → orquestación + transacción
InventoryValuationService → FIFO / costo real (debe ser el único punto que calcula costo de venta)
ExchangeRateService     → ingestión + snapshot, nunca recalcula histórico
```
Aislar `PricingService` como función pura (sin acceso a BD) facilita muchísimo el testing.

---

## 4. Base de datos

### 4.1 Lo correcto
- Uso de `numeric`/`decimal` en vez de `float` para dinero: imprescindible, bien señalado.
- Modelo de atributos flexibles (`attributes`/`attribute_values`/`product_variants`) es el patrón EAV correcto para productos con variantes heterogéneas (ropa vs. bisutería).
- Kardex (`inventory_movements`) en vez de solo actualizar `stock`: correcto y necesario para auditoría.

### 4.2 Ajustes recomendados al modelo propuesto

1. **Volumen de `inventory_movements` y `exchange_rates`**: son las tablas de mayor crecimiento. Desde el diseño inicial conviene:
   - Índices compuestos por `(product_variant_id, location_id, created_at)`.
   - Particionamiento por rango de fecha (PostgreSQL native partitioning) si se espera más de un par de años de operación continua, para que los reportes no degraden con el tiempo.

2. **Precisión numérica diferenciada por moneda** (el documento lo menciona pero sin definir valores):
   ```sql
   -- USDT / tasas
   numeric(18,6)
   -- Bs (montos altos, sin decimales relevantes en la práctica)
   numeric(18,2)
   -- COP (igual, montos altos)
   numeric(18,2)
   ```

3. **Constraint de no-negatividad de stock**: agregar `CHECK (quantity >= 0)` a nivel de tabla de stock agregada, además de la lógica de aplicación — es la última línea de defensa contra sobreventa por condición de carrera.

4. **Unicidad de SKU**: `UNIQUE` a nivel de base de datos sobre `product_variants.sku`, no solo validación en Laravel.

5. **Soft delete / estado `cancelled`**: correcto como está planteado (no eliminar transacciones financieras). Sugerencia adicional: usar un estado explícito por tabla (`sales.status`, `purchases.status`) en vez de un flag booleano genérico, porque una venta cancelada necesita disparar reversión de inventario, mientras que un gasto cancelado no.

6. **`profit_distributions` con snapshot del % de socio**: el porcentaje de cada socio puede cambiar con el tiempo (nuevos aportes). La distribución histórica debe guardar el porcentaje **vigente en el momento del cálculo**, no referenciar el porcentaje actual del socio.

7. **Falta explícita en el modelo**: una tabla `stock_summary` (o vista materializada) por `product_variant_id + location_id` que se mantenga como saldo corriente, alimentada por `inventory_movements`. Sin esto, cada consulta de "cuánto stock tengo" tendría que sumar el kardex completo, lo cual no escala.

### 4.3 Diagrama de relación ajustado (resumen)
```
inventory_lots ──< sale_item_lot_consumptions >── sale_items
      │
      └── snapshot: unit_cost_usdt, purchase_id, exchange_rate usado en la compra

exchange_rates (histórico, inmutable)
      │
      └── se COPIA (no se referencia únicamente) a: sales, purchases, expenses, conversions
```

---

## 5. Seguridad y auditoría

- El esquema de roles (Administrador / Socio / Vendedor / Almacén) es razonable como punto de partida. Sugerencia: usar un paquete de permisos granular (Spatie Laravel-Permission) en lugar de roles hardcodeados, para poder ajustar accesos sin desplegar código.
- La auditoría (`audit_logs`) debe implementarse con un *observer* genérico de Eloquent sobre los modelos sensibles, no con llamadas manuales dispersas en cada servicio — de lo contrario es fácil olvidar registrar un cambio.
- Falta mencionar autenticación de dos factores para roles con acceso a capital/utilidades — dado que se manejan fondos reales en USDT, es una medida barata con alto valor.

---

## 6. Lo que el documento no menciona y sí debería considerarse

| Tema | Por qué importa |
|---|---|
| Testing automatizado | Sin esto, cualquier cambio en `PricingService` es un riesgo financiero directo |
| CI/CD | Evita desplegar cálculos financieros rotos a producción |
| Idempotencia de jobs de tasas | Evita duplicar o corromper el histórico de tasas |
| Particionamiento de tablas de alto volumen | Sin esto, reportes e inventario se vuelven lentos en 12–18 meses |
| Vista/tabla de saldo corriente de stock | Sin esto, "cuánto tengo" se vuelve una consulta cara |
| Manejo de fallos de la fuente de tasas externas | El sistema no puede quedar "ciego" si la fuente de BCV/USDT cae |
| Política de redondeo consistente | Con tres monedas y conversiones encadenadas, un redondeo distinto en cada capa genera descuadres acumulados — definir una sola regla (ej. redondeo bancario a 2 decimales en moneda final, 6 en USDT) |
| Doble entrada contable (partida doble) | No es obligatorio para el MVP, pero si el negocio crece, migrar `cash_movements`/`profit_distributions` hacia un modelo de partida doble evitará descuadres de caja difíciles de rastrear |

---

## 7. Priorización sugerida (ajuste al roadmap del documento original)

El documento ya propone 6 fases, que en general están bien secuenciadas. El ajuste que recomiendo es **mover testing y el modelo FIFO con `sale_item_lot_consumptions` a la Fase 1**, no dejarlos implícitos:

1. **Fase 0 (nueva, antes de todo)**: infraestructura base con Docker, staging, CI con tests, y decisión final de precisión numérica/redondeo. Esto evita rehacer migraciones después.
2. **Fase 1 — Núcleo**: igual a la propuesta, agregando `sale_item_lot_consumptions` y `stock_summary` desde el inicio.
3. **Fase 2 — Ventas**: igual, con tests de concurrencia sobre inventario incluidos como criterio de "hecho".
4. **Fase 3 — Finanzas**: igual, con foco especial en que ningún cálculo de utilidad recalcule tasas históricas (test explícito para esto).
5. **Fase 4 — Sociedad**: igual, con snapshot de porcentaje de socio en cada distribución.
6. **Fase 5 y 6**: sin cambios respecto al documento original.

---

## 8. Conclusión

El diseño conceptual es sólido y muestra comprensión real del problema de negocio (doble tipo de cambio, operación en dos países, necesidad de separar capital/utilidad). El riesgo no está en la visión general sino en los detalles de implementación que hoy quedan implícitos: modelo de consumo de lotes para FIFO, snapshot explícito de tasas y costos en cada transacción, control de concurrencia sobre inventario, y ausencia total de estrategia de testing/CI. Ninguno de estos puntos invalida la arquitectura propuesta (Laravel + PostgreSQL + Livewire + Redis sigue siendo la elección correcta para este tamaño de negocio); simplemente son las piezas que separan una "buena idea documentada" de un sistema que va a manejar dinero real de forma confiable durante años.